﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Framework.Common.HashDFA
{
    public struct StartEnd
    {
        /// <summary>
        /// 脏字第一个字符在字符串中的位置
        /// </summary>
        public int Start { get; set; }
        /// <summary>
        /// 脏字最后一个字符在字符串的位置
        /// </summary>
        public int End { get; set; }
    }
    /// <summary>
    /// 其中一个关键词包含另一个关键词 认为是关键词重叠(应在字典级别避免此类问题)
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class DFADict<T>
    {
        public Dictionary<T, DFADict<T>> Dict { get; set; } //dict 用来正向查找
        public DFADict<T> Parent { get; set; }

        /// <summary>
        /// 插入一条记录
        /// </summary>
        /// <param name="source"></param>
        public void Add(IEnumerable<T> source)
        {
            var parent = this;
            foreach (var single in source)
            {
                if (parent.Dict == null)
                {
                    parent.Dict = new Dictionary<T, DFADict<T>>();
                }
                DFADict<T> tsub = null;
                if (!parent.Dict.ContainsKey(single))
                {
                    tsub = new DFADict<T>();
                    tsub.Parent = parent;
                    parent.Dict[single] = tsub;
                }
                else
                {
                    tsub = parent.Dict[single];
                }
                parent = tsub;
            }
        }
        /// <summary>
        /// 是否包含脏字
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        public bool Contains(T[] source)
        {
            DFADict<T> parent = this;
            int index = 0;
            int maxLength = source.Length;
            int offset = 0;//用于判断关键字长度
            while (maxLength >= index)
            {
                if (parent.Dict == null)
                {
                    return true;
                }
                else
                {
                    if (maxLength > index)
                    {
                        var single = source[index];
                        if (parent.Dict.ContainsKey(single))
                        {
                            index++;
                            offset++;
                            parent = parent.Dict[single];
                        }
                        else
                        {
                            index = index + 1 - offset;
                            offset = 0;
                            parent = this;
                        }
                    }
                    else
                    {
                        index = index + 1 - offset;
                        offset = 0;
                        parent = this;
                    }
                }
            }
            return false;
        }

        public IEnumerable<StartEnd> Match(T[] source)
        {
            DFADict<T> parent = this;
            int index = 0;
            int maxLength = source.Length;
            int offset = 0;//用于判断关键字长度
            while (maxLength >= index)
            {
                if (parent.Dict == null)
                {
                    var kp = new StartEnd { Start = index - offset, End = index - 1 };
                    yield return kp;
                    parent = this;
                    offset = 0;
                }
                else
                {
                    if (maxLength > index)
                    {
                        var single = source[index];
                        if (parent.Dict.ContainsKey(single))
                        {
                            index++;
                            offset++;
                            parent = parent.Dict[single];
                        }
                        else
                        {
                            index = index + 1 - offset;
                            offset = 0;
                            parent = this;
                        }
                    }
                    else
                    {
                        index = index + 1 - offset;
                        offset = 0;
                        parent = this;
                    }
                }
            }

        }
    }
}
